﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Zive.Color;

namespace LabColorPicker {

    public partial class ColorPickerWindow: Window {

        private ColorData _colorData = new ColorData( );
        public ColorData ColorData {
            get { return _colorData; }
            set { _colorData = value; }
        }

        private ColorData _originalColorData;

        private readonly SolidColorBrush _currentSwatchBrush = new SolidColorBrush( );
        private readonly SolidColorBrush _originalSwatchBrush = new SolidColorBrush( );

        private readonly RgbOneChannelBitmapMaker _rgbOneChannelBitmapMaker = new RgbOneChannelBitmapMaker( 32, 256 );
        private readonly RgbTwoChannelBitmapMaker _rgbTwoChannelBitmapMaker = new RgbTwoChannelBitmapMaker( 256, 256 );

        private readonly LabOneChannelBitmapMaker _labOneChannelBitmapMaker = new LabOneChannelBitmapMaker( 32, 256 );
        private readonly LabTwoChannelBitmapMaker _labTwoChannelBitmapMaker = new LabTwoChannelBitmapMaker( 256, 256 );

        private readonly XyzOneChannelBitmapMaker _xyzOneChannelBitmapMaker = new XyzOneChannelBitmapMaker( 32, 256 );
        private readonly XyzTwoChannelBitmapMaker _xyzTwoChannelBitmapMaker = new XyzTwoChannelBitmapMaker( 256, 256 );

        private OneChannelBitmapMaker _oneChannelBitmapMaker;
        private TwoChannelBitmapMaker _twoChannelBitmapMaker;

        public ColorPickerWindow( ) {
            InitializeComponent( );

            swatchOriginal.Background = _originalSwatchBrush;
            swatchCurrent.Background = _currentSwatchBrush;

            _twoChannelBitmapMaker = _labTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _labOneChannelBitmapMaker;

            _colorData.PropertyChanged += ColorData_PropertyChanged;
            //_colorData.Rgb = new RgbColor( 40, 116, 244 );
            _colorData.Lab = new LabColor( Illuminants.D50, 50d, 0d, 0d );
            _originalSwatchBrush.Color = _colorData.Rgb;

            radioLabL.IsChecked = true;
        }

        //
        // TwoDimensionalSlice
        //

        private void TwoDimensionalSlice_PropertyChanged( object sender, PropertyChangedEventArgs ev ) {
            if ( "HorizontalValue" == ev.PropertyName ) {
                var newValue = TwoDimensionalSlice.HorizontalValue;
                if ( _twoChannelBitmapMaker is LabTwoChannelBitmapMaker ) {
                    _colorData.Lab[ _labTwoChannelBitmapMaker.HorizontalChannel ] = newValue;
                } else if ( _twoChannelBitmapMaker is RgbTwoChannelBitmapMaker ) {
                    _colorData.Rgb[ _rgbTwoChannelBitmapMaker.HorizontalChannel ] = newValue;
                } else if ( _twoChannelBitmapMaker is XyzTwoChannelBitmapMaker ) {
                    _colorData.Xyz[ _xyzTwoChannelBitmapMaker.HorizontalChannel ] = newValue;
                }
                return;
            }

            if ( "VerticalValue" == ev.PropertyName ) {
                var newValue = TwoDimensionalSlice.VerticalValue;
                if ( _twoChannelBitmapMaker is LabTwoChannelBitmapMaker ) {
                    _colorData.Lab[ _labTwoChannelBitmapMaker.VerticalChannel ] = newValue;
                } else if ( _twoChannelBitmapMaker is RgbTwoChannelBitmapMaker ) {
                    _colorData.Rgb[ _rgbTwoChannelBitmapMaker.VerticalChannel ] = newValue;
                } else if ( _twoChannelBitmapMaker is XyzTwoChannelBitmapMaker ) {
                    _colorData.Xyz[ _xyzTwoChannelBitmapMaker.VerticalChannel ] = newValue;
                }
                return;
            }
        }

        private void TwoDimensionalSlice_ValueChanged( object sender, EventArgs ev ) {
            var newHorizontalValue = TwoDimensionalSlice.HorizontalValue;
            var newVerticalValue = TwoDimensionalSlice.VerticalValue;
            if ( _twoChannelBitmapMaker is LabTwoChannelBitmapMaker ) {
                _colorData.Lab[ _labTwoChannelBitmapMaker.HorizontalChannel ] = newHorizontalValue;
                _colorData.Lab[ _labTwoChannelBitmapMaker.VerticalChannel ] = newVerticalValue;
            } else if ( _twoChannelBitmapMaker is RgbTwoChannelBitmapMaker ) {
                _colorData.Rgb[ _rgbTwoChannelBitmapMaker.HorizontalChannel ] = newHorizontalValue;
                _colorData.Rgb[ _rgbTwoChannelBitmapMaker.VerticalChannel ] = newVerticalValue;
            } else if ( _twoChannelBitmapMaker is XyzTwoChannelBitmapMaker ) {
                _colorData.Xyz[ _xyzTwoChannelBitmapMaker.HorizontalChannel ] = newHorizontalValue;
                _colorData.Xyz[ _xyzTwoChannelBitmapMaker.VerticalChannel ] = newVerticalValue;
            }
        }

        //
        // OneDimensionalSlice
        //

        private void OneDimensionalSlice_PropertyChanged( object sender, PropertyChangedEventArgs ev ) {
            if ( "Value" != ev.PropertyName ) {
                return;
            }

            var newValue = OneDimensionalSlice.Value;
            if ( _oneChannelBitmapMaker is LabOneChannelBitmapMaker ) {
                _colorData.Lab[ _labOneChannelBitmapMaker.Channel ] = newValue;
            } else if ( _oneChannelBitmapMaker is RgbOneChannelBitmapMaker ) {
                _colorData.Rgb[ _rgbOneChannelBitmapMaker.Channel ] = newValue;
            } else if ( _oneChannelBitmapMaker is XyzOneChannelBitmapMaker ) {
                _colorData.Xyz[ _xyzOneChannelBitmapMaker.Channel ] = newValue;
            }
        }

        //
        // RGB radio buttons
        //

        private void radioRgbR_Checked( object sender, RoutedEventArgs ev ) {
            _rgbTwoChannelBitmapMaker.HorizontalChannel = RgbChannels.B;
            _rgbTwoChannelBitmapMaker.VerticalChannel = RgbChannels.G;
            _rgbOneChannelBitmapMaker.Channel = RgbChannels.R;

            HorizontalAxisLabel.Content = "B";
            VerticalAxisLabel.Content = "G";
            SingleAxisLabel.Content = "R";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                0d, 255d, _colorData.Rgb.B,
                0d, 255d, _colorData.Rgb.G
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 255d, _colorData.Rgb.R
            );

            _twoChannelBitmapMaker = _rgbTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _rgbOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        private void radioRgbG_Checked( object sender, RoutedEventArgs ev ) {
            _rgbTwoChannelBitmapMaker.HorizontalChannel = RgbChannels.B;
            _rgbTwoChannelBitmapMaker.VerticalChannel = RgbChannels.R;
            _rgbOneChannelBitmapMaker.Channel = RgbChannels.G;

            HorizontalAxisLabel.Content = "B";
            VerticalAxisLabel.Content = "R";
            SingleAxisLabel.Content = "G";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                0d, 255d, _colorData.Rgb.B,
                0d, 255d, _colorData.Rgb.R
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 255d, _colorData.Rgb.G
            );

            _twoChannelBitmapMaker = _rgbTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _rgbOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        private void radioRgbB_Checked( object sender, RoutedEventArgs ev ) {
            _rgbTwoChannelBitmapMaker.HorizontalChannel = RgbChannels.R;
            _rgbTwoChannelBitmapMaker.VerticalChannel = RgbChannels.G;
            _rgbOneChannelBitmapMaker.Channel = RgbChannels.B;

            HorizontalAxisLabel.Content = "R";
            VerticalAxisLabel.Content = "G";
            SingleAxisLabel.Content = "B";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                0d, 255d, _colorData.Rgb.R,
                0d, 255d, _colorData.Rgb.G
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 255d, _colorData.Rgb.B
            );

            _twoChannelBitmapMaker = _rgbTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _rgbOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        //
        // L*a*b* radio buttons
        //

        private void radioLabL_Checked( object sender, RoutedEventArgs ev ) {
            _labTwoChannelBitmapMaker.HorizontalChannel = LabChannels.A;
            _labTwoChannelBitmapMaker.VerticalChannel = LabChannels.B;
            _labOneChannelBitmapMaker.Channel = LabChannels.L;

            HorizontalAxisLabel.Content = "a*";
            VerticalAxisLabel.Content = "b*";
            SingleAxisLabel.Content = "L*";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                -128d, 128d, _colorData.Lab.Astar,
                -128d, 128d, _colorData.Lab.Bstar
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 100d, _colorData.Lab.Lstar
            );

            _twoChannelBitmapMaker = _labTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _labOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        private void radioLabA_Checked( object sender, RoutedEventArgs ev ) {
            _labTwoChannelBitmapMaker.HorizontalChannel = LabChannels.B;
            _labTwoChannelBitmapMaker.VerticalChannel = LabChannels.L;
            _labOneChannelBitmapMaker.Channel = LabChannels.A;

            HorizontalAxisLabel.Content = "b*";
            VerticalAxisLabel.Content = "L*";
            SingleAxisLabel.Content = "a*";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                -128d, 128d, _colorData.Lab.Bstar,
                0d, 100d, _colorData.Lab.Lstar
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                -128d, 128d, _colorData.Lab.Astar
            );

            _twoChannelBitmapMaker = _labTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _labOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        private void radioLabB_Checked( object sender, RoutedEventArgs ev ) {
            _labTwoChannelBitmapMaker.HorizontalChannel = LabChannels.A;
            _labTwoChannelBitmapMaker.VerticalChannel = LabChannels.L;
            _labOneChannelBitmapMaker.Channel = LabChannels.B;

            HorizontalAxisLabel.Content = "a*";
            VerticalAxisLabel.Content = "L*";
            SingleAxisLabel.Content = "b*";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                -128d, 128d, _colorData.Lab.Astar,
                0d, 100d, _colorData.Lab.Lstar
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                -128d, 128d, _colorData.Lab.Bstar
            );

            _twoChannelBitmapMaker = _labTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _labOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        //
        // XYZ radio buttons
        //

        private void radioXyzX_Checked( object sender, RoutedEventArgs ev ) {
            _xyzTwoChannelBitmapMaker.HorizontalChannel = XyzChannels.Z;
            _xyzTwoChannelBitmapMaker.VerticalChannel = XyzChannels.Y;
            _xyzOneChannelBitmapMaker.Channel = XyzChannels.X;

            HorizontalAxisLabel.Content = "Z";
            VerticalAxisLabel.Content = "Y";
            SingleAxisLabel.Content = "X";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                0d, 1d, _colorData.Xyz.Z,
                0d, 1d, _colorData.Xyz.Y
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 1d, _colorData.Xyz.X
            );

            _twoChannelBitmapMaker = _xyzTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _xyzOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        private void radioXyzY_Checked( object sender, RoutedEventArgs ev ) {
            _xyzTwoChannelBitmapMaker.HorizontalChannel = XyzChannels.Z;
            _xyzTwoChannelBitmapMaker.VerticalChannel = XyzChannels.X;
            _xyzOneChannelBitmapMaker.Channel = XyzChannels.Y;

            HorizontalAxisLabel.Content = "Z";
            VerticalAxisLabel.Content = "X";
            SingleAxisLabel.Content = "Y";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                0d, 1d, _colorData.Xyz.Z,
                0d, 1d, _colorData.Xyz.X
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 1d, _colorData.Xyz.Y
            );

            _twoChannelBitmapMaker = _xyzTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _xyzOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        private void radioXyzZ_Checked( object sender, RoutedEventArgs ev ) {
            _xyzTwoChannelBitmapMaker.HorizontalChannel = XyzChannels.X;
            _xyzTwoChannelBitmapMaker.VerticalChannel = XyzChannels.Y;
            _xyzOneChannelBitmapMaker.Channel = XyzChannels.Z;

            HorizontalAxisLabel.Content = "X";
            VerticalAxisLabel.Content = "Y";
            SingleAxisLabel.Content = "Z";

            TwoDimensionalSlice.SetMinimaMaximaAndValues(
                0d, 1d, _colorData.Xyz.X,
                0d, 1d, _colorData.Xyz.Y
            );
            OneDimensionalSlice.SetMinimumMaximumAndValue(
                0d, 1d, _colorData.Xyz.Z
            );

            _twoChannelBitmapMaker = _xyzTwoChannelBitmapMaker;
            _oneChannelBitmapMaker = _xyzOneChannelBitmapMaker;
            _UpdateSliceBitmaps( );
        }

        //
        // ColorData
        //

        private void _UpdateSliceBitmaps( ) {
            TwoDimensionalSlice.Source = _twoChannelBitmapMaker.Bitmap;
            OneDimensionalSlice.Source = _oneChannelBitmapMaker.Bitmap;
        }

        protected void ColorData_PropertyChanged( object sender, PropertyChangedEventArgs ev ) {
            if ( null == _originalColorData ) {
                _originalColorData = new ColorData( _colorData );
            }

            switch ( ev.PropertyName ) {
                case "Rgb":
                    _rgbOneChannelBitmapMaker.Color = _colorData.Rgb;
                    _rgbTwoChannelBitmapMaker.Color = _colorData.Rgb;
                    if ( _oneChannelBitmapMaker is RgbOneChannelBitmapMaker ) {
                        _UpdateSliceBitmaps( );
                    }
                    textWebColor.Text = string.Format( "#{0,2:X2}{1,2:X2}{2,2:X2}", _colorData.Rgb.ByteR, _colorData.Rgb.ByteG, _colorData.Rgb.ByteB );
                    _currentSwatchBrush.Color = _colorData.Rgb;
                    break;

                case "Lab":
                    _labOneChannelBitmapMaker.Color = _colorData.Lab;
                    _labTwoChannelBitmapMaker.Color = _colorData.Lab;
                    if ( _oneChannelBitmapMaker is LabOneChannelBitmapMaker ) {
                        _UpdateSliceBitmaps( );
                    }
                    break;

                case "Xyz":
                    _xyzOneChannelBitmapMaker.Color = _colorData.Xyz;
                    _xyzTwoChannelBitmapMaker.Color = _colorData.Xyz;
                    if ( _oneChannelBitmapMaker is XyzOneChannelBitmapMaker ) {
                        _UpdateSliceBitmaps( );
                    }
                    break;
            }
        }

        private void swatchOriginal_MouseLeftButtonDown( object sender, MouseButtonEventArgs ev ) {
            _colorData.Xyz = _originalColorData.Xyz;
        }

    }

}
